﻿/*******************************************************************************
 * AAEngine
 * Copyright (c) 2010 Mike Jarosch
 *
 * Original source PushButton Engine:
 * Copyright (C) 2009 PushButton Labs, LLC
 * For more information see http://www.pushbuttonengine.com
 *
 * This file is licensed under the terms of the MIT license, which is included
 * in the "MIT License.txt" file at the root directory of this SDK.
 ******************************************************************************/

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content;
using AAEngine.Engine.Debug;
using AAEngine.Engine.Serialization;

namespace AAEngine.Engine.Resources
{
    public class ResourceManager : ContentManager
    {
        private Dictionary<string, object> _resources = new Dictionary<string, object>();

        public ResourceManager(IServiceProvider serviceProvider)
            : base(serviceProvider)
        {
        }

        public ResourceManager(IServiceProvider serviceProvider, string rootDirectory)
            : base(serviceProvider, rootDirectory)
        {
        }

        public override T Load<T>(string assetName)
        {
            return Load<T>(assetName, false);
        }

#if WINDOWS_PHONE || XBOX
        public T Load<T>(string assetName, bool forceReload)
#else
        public T Load<T>(string assetName, bool forceReload = false)
#endif
        {
            if (_resources.ContainsKey(assetName) && forceReload == false)
            {
                return (T)_resources[assetName];
            }

            T resource = base.ReadAsset<T>(assetName, RecordDisposableObject);
            _resources[assetName] = resource;

            return resource;
        }

#if WINDOWS_PHONE || XBOX
        public Resource Load(string assetName, Type resourceType)
        {
            return Load(assetName, resourceType, false);
        }

        public Resource Load(string assetName, Type resourceType, bool forceReload)
#else
        public Resource Load(string assetName, Type resourceType, bool forceReload = false)
#endif
        {
            if (String.IsNullOrEmpty(assetName))
            {
                Logger.Error(this, "Load", "Cannot load a resource with an empty filename.");
                return null;
            }

            object resource;
            _resources.TryGetValue(assetName, out resource);
            if (resource != null && forceReload == true)
            {
                if ((resource as IDisposable) != null)
                {
                    ((IDisposable)resource).Dispose();
                }
                _resources.Remove(assetName);
            }

            if (resource == null)
            {
                object data = base.ReadAsset<object>(assetName, RecordDisposableObject);

                if (resourceType == null)
                {
                    resource = data;
                }
                else
                {
                    resource = TypeUtility.Instantiate(resourceType.FullName);
                }

                if ((resource as Resource) != null)
                {
                    ((Resource)resource).Initialize(data);
                    ((Resource)resource).Filename = assetName;
                }

                _resources[assetName] = resource;
            }

            if (resource as Resource != null)
            {
                ((Resource)resource).IncrementReferenceCount();
            }

            return (Resource)resource;
        }

        public override void Unload()
        {
            foreach (string key in _resources.Keys)
            {
                IDisposable disposable = _resources[key] as IDisposable;
                if (disposable != null)
                {
                    disposable.Dispose();
                }
            }

            _resources.Clear();
        }

        public void Unload(string assetName)
        {
            object resource;
            _resources.TryGetValue(assetName, out resource);

            if (resource == null)
            {
                Logger.Warn(this, "Unload", "The resource from file '" + assetName + "' is not loaded.");
                return;
            }

            if (resource as Resource != null)
            {
                ((Resource)resource).DecrementReferenceCount();

                if (((Resource)resource).ReferenceCount < 1)
                {
                    ((Resource)resource).Dispose();

                    _resources.Remove(assetName);
                }

                return;
            }
            
            if (resource as IDisposable != null)
            {
                ((IDisposable)resource).Dispose();
            }

            _resources.Remove(assetName);
        }

        private void RecordDisposableObject(IDisposable disposable)
        {
            //_disposables.Add(disposable);
        }
    }
}
